﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Collections;

namespace ESLReminder.Modules
{
    public partial class ProcessModuleConfigPanel : UserControl
    {
        private class EnumValue<T>
        {
            T m_Value;
            public T Value
            {
                get
                { return m_Value; }
            }
            public EnumValue(T prio)
            {
                m_Value = prio;
            }
            public override string ToString()
            {
                string raw = Enum.GetName(typeof(T), m_Value);
                string value = Properties.Resources.ResourceManager.GetString(raw);
                return value == null ? raw : value;
            }
            public static void FillComboBox(ComboBox cmb)
            {
                Array processtypes = Enum.GetValues(typeof(T));
                foreach (T o in processtypes)
                {
                    cmb.Items.Add(new EnumValue<T>(o));
                }
            }
        }
        ProcessModule pm;
        ProcessSetting m_SelectedSetting = null;

        public ProcessSetting SelectedSetting
        {
            get { return m_SelectedSetting; }
            set { m_SelectedSetting = value; }
        }

        ListViewItem m_SelectedItem = null;
        private class ProcessNameComparer : IComparer
        {
            int IComparer.Compare(object a, object b)
            {
                Process c1 = (Process)a;
                Process c2 = (Process)b;
                return c1.ProcessName.CompareTo(c2.ProcessName);
            }
        }

        public ListViewItem AddToList(ProcessSetting ps)
        {
            ListViewItem i = new ListViewItem(ps.Name);
            i.Tag = ps;
            i.SubItems.Add(Enum.GetName(typeof(ProcessType), ps.ProcessType));
            i.SubItems.Add(AffinityToString(ps.CPUAffinity));
            i.SubItems.Add(Enum.GetName(typeof(ProcessPriorityClass), ps.Priority));
            return listView1.Items.Add(i);
        }

        public ProcessModuleConfigPanel(ProcessModule module)
        {
            InitializeComponent();

            BackColor = Color.Transparent;
            pm = module;
            listView1.Items.Clear();
            ProcessSetting[] settings = pm.ProcessRules;
            foreach (ProcessSetting ps in settings)
            {
                AddToList(ps);
            }
            for (int i = 0; i < Environment.ProcessorCount; ++i)
            {
                CheckBox cb = new CheckBox();
                cb.Text = String.Format("CPU{0}", i);
                cb.Tag = i;
                cb.AutoSize = true;
                cb.CheckedChanged += new EventHandler(cb_CheckedChanged);

                CPUCheckBoxPanel.Controls.Add(cb);
            }
            EnumValue<ProcessPriorityClass>.FillComboBox(cmbPriority);
            EnumValue<ProcessType>.FillComboBox(cmbType);

            Process[] procs = Process.GetProcesses();
            Array.Sort(procs, new ProcessNameComparer());
            foreach (Process p in procs)
            {
                if (!cmbName.Items.Contains(p.ProcessName.ToLower()))
                    cmbName.Items.Add(p.ProcessName.ToLower());
                p.Dispose();
            }


            listView1_SelectedIndexChanged(this, EventArgs.Empty);
        }

        void UpdateItem(ListViewItem i)
        {
            if (i == null)
                return;
            ProcessSetting ps = i.Tag as ProcessSetting;
            i.SubItems[0].Text = ps.Name;
            i.SubItems[1].Text = Enum.GetName(typeof(ProcessType), ps.ProcessType);
            i.SubItems[2].Text = AffinityToString(ps.CPUAffinity);
            i.SubItems[3].Text = Enum.GetName(typeof(ProcessPriorityClass), ps.Priority);
        }

        void cb_CheckedChanged(object sender, EventArgs e)
        {
            if (m_SelectedSetting == null)
                return;
            int newvalue = 0;
            for (int i = 0; i < CPUCheckBoxPanel.Controls.Count; ++i)
            {
                CheckBox cb = CPUCheckBoxPanel.Controls[i] as CheckBox;
                if (cb.Checked && cb.Enabled)
                    newvalue |= (1 << i);
            }
            m_SelectedSetting.CPUAffinity = newvalue;
            UpdateItem(m_SelectedItem);
        }
        private string AffinityToString(int affinity)
        {
            StringBuilder b = new StringBuilder();
            for (int i = 0; i < Environment.ProcessorCount; ++i)
            {
                if ((affinity & (1 << i)) != 0)
                {
                    if (b.Length != 0)
                        b.Append(' ');
                    b.AppendFormat("CPU{0}", i);
                }
            }
            return b.ToString();
        }
        private void listView1_SelectedIndexChanged(object sender, EventArgs e)
        {
            processSettingBindingSource.Clear();
            if (listView1.SelectedItems.Count == 1)
            {
                m_SelectedSetting = listView1.SelectedItems[0].Tag as ProcessSetting;
                processSettingBindingSource.Add(m_SelectedSetting);
                m_SelectedItem = listView1.SelectedItems[0];
                for (int i=0; i < CPUCheckBoxPanel.Controls.Count; ++i)
                {
                    CheckBox cb = CPUCheckBoxPanel.Controls[i] as CheckBox;
                    cb.CheckedChanged -= new EventHandler(cb_CheckedChanged);
                    cb.Checked = (m_SelectedSetting.CPUAffinity & (1 << i)) != 0;
                    cb.CheckedChanged += new EventHandler(cb_CheckedChanged);
                }
                CPUCheckBoxPanel.Enabled = true;
                cmbName.Enabled = true;
                cmbPriority.Enabled = true;
                cmbType.Enabled = true;
                cbKill.Enabled = true;
                bUp.Enabled = true;
                bDown.Enabled = true;
                /*cbKill.CheckedChanged -= new EventHandler(cbKill_CheckedChanged);
                
                cbKill.CheckedChanged += new EventHandler(cbKill_CheckedChanged);*/

                //cmbName.Text = m_SelectedSetting.Name;
                foreach (EnumValue<ProcessType> val in cmbType.Items)
                {
                    if (val.Value == m_SelectedSetting.ProcessType)
                    {
                        cmbType.SelectedItem = val;
                        break;
                    }
                }
                foreach (EnumValue<ProcessPriorityClass> val in cmbPriority.Items)
                {
                    if (val.Value == m_SelectedSetting.Priority)
                    {
                        cmbPriority.SelectedItem = val;
                        break;
                    }
                }
            }
            else
            {
                m_SelectedSetting = null;
                m_SelectedItem = null;
                CPUCheckBoxPanel.Enabled = false;
                for (int i = 0; i < CPUCheckBoxPanel.Controls.Count; ++i)
                {
                    CheckBox cb = CPUCheckBoxPanel.Controls[i] as CheckBox;
                    cb.Checked = false;
                }
                //cmbName.Enabled = false;
                cmbPriority.Enabled = false;
                cmbType.Enabled = false;
                cmbType.SelectedItem = null;
                cmbPriority.SelectedItem = null;
                cbKill.Enabled = false;
                bUp.Enabled = false;
                bDown.Enabled = false;
                //cmbName.SelectedValue = null;
            }
        }

        void cbKill_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox cb = sender as CheckBox;
            m_SelectedSetting.Kill = cb.Checked;
        }

        private void cmdType_SelectionChangeCommitted(object sender, EventArgs e)
        {
            if (m_SelectedSetting != null)
            {
                m_SelectedSetting.ProcessType = ((EnumValue<ProcessType>)cmbType.SelectedItem).Value;
                UpdateItem(m_SelectedItem);
            }
        }

        private void cmbPriority_SelectionChangeCommitted(object sender, EventArgs e)
        {
            if (m_SelectedSetting != null)
            {
                m_SelectedSetting.Priority = ((EnumValue<ProcessPriorityClass>)cmbPriority.SelectedItem).Value;
                UpdateItem(m_SelectedItem);
            }
        }

        private void bAdd_Click(object sender, EventArgs e)
        {
            ProcessSetting ps = pm.CreateNew();
            foreach (ListViewItem i in listView1.SelectedItems)
                i.Selected = false;
            ListViewItem newitem = AddToList(ps);
            newitem.Selected = true;
            listView1_SelectedIndexChanged(this, EventArgs.Empty);
        }

        private void bRemove_Click(object sender, EventArgs e)
        {
            //TODO: Lokalisieren
            if (m_SelectedSetting != null && MessageBox.Show(this,"Are you sure you want to delete the selected item?","Are you sure?", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                pm.Remove(m_SelectedSetting);
                listView1.Items.Remove(m_SelectedItem);
                m_SelectedSetting = null;
                m_SelectedItem = null;
            }
        }

        private void processSettingBindingSource_CurrentItemChanged(object sender, EventArgs e)
        {
            UpdateItem(m_SelectedItem);
        }

        private void bUp_Click(object sender, EventArgs e)
        {

        }

        private void bDown_Click(object sender, EventArgs e)
        {

        }
    }
}
